Skip to content

[TRTLLMINF-188][infra] Require approval for broad post-merge bot runs#16318

Merged
chzblych merged 7 commits into
NVIDIA:mainfrom
chzblych:trtllminf-188-post-merge-approval
Jul 19, 2026
Merged

[TRTLLMINF-188][infra] Require approval for broad post-merge bot runs#16318
chzblych merged 7 commits into
NVIDIA:mainfrom
chzblych:trtllminf-188-post-merge-approval

Conversation

@chzblych

@chzblych chzblych commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Description

TRTLLMINF-188 reduces accidental consumption of shared CI resources by requiring the ci: post-merge approved label before broad post-merge bot runs are dispatched.

This PR:

  • Adds the default-branch Guard Post-Merge Approval Label workflow.
  • Validates the latest approval-label event actor against active membership in NVIDIA/trt-llm-ci-approvers.
  • Normally removes the label and posts an explanatory PR comment when the actor is unauthorized or membership cannot be verified.
  • Serializes Guard runs per PR and binds cleanup to the exact label event, so an older unauthorized run does not remove a newer approval.
  • Keeps a Guard job that has already started eligible to attempt cleanup after standard workflow cancellation, with a five-minute job timeout.
  • Uses pull_request_target only for static default-branch API logic and never checks out or executes PR-controlled code.
  • Keeps the approval label when new commits are pushed.
  • Compares approval-label identity case-insensitively.
  • Updates /bot help and CI documentation while preserving explicit stage names and limited wildcard behavior such as *PerfSanity*.

The companion Jenkins change in trtllm-github-ci!86 refreshes current PR labels during command validation and immediately before downstream dispatch. It requires the approval label for:

  • --post-merge
  • --stage-list "*" and --extra-stage "*"
  • --stage-list "*Post-Merge*" and --extra-stage "*Post-Merge*"
  • the same broad selectors after trimming whitespace, removing escaping backslashes, collapsing repeated *, or placing them in comma-separated selector lists

Selector matching remains case-sensitive, consistent with downstream stage selection. Approval-label identity is handled case-insensitively by both the workflow and Jenkins.

The membership lookup uses TRTLLM_AGENT_SHARED_TOKEN; label cleanup and PR comments use the scoped GITHUB_TOKEN.

Scope and limitations

This is a best-effort CI resource-governance guard, not a strict authorization boundary. Jenkins checks current label presence but does not synchronously revalidate the label actor or Team membership. A Guard job that has started can attempt cleanup after standard cancellation, but queued-before-start cancellation, force-cancel, runner/service failure, and the immediate asynchronous label-to-dispatch window are not fully covered. TRTLLMINF-220 tracks the stronger guarantee and follow-up design.

The canonical .github/workflows/blossom-ci.yml has no diff in this PR.

Validation

Source and isolated Jenkins checks

  • Validated post-merge-approval.yml SHA-256: 7e67834e0ede75ce84e74bf78a5d4a5fdc744b609fc6ae10b1eeb29b00f51cf5.
  • YAML parsing, embedded github-script compilation, focused case-insensitive label validation/cleanup simulation, and git diff --check passed.
  • A retained controller-only Jenkins Sandbox run passed without network access or real downstream dispatch. The tested Jenkinsfile is byte-identical to the companion MR head, SHA-256 08886d03b7f49c6b86982ff134559e8f323c0be9224850298345c897e8f21905.
  • The companion MR exact-head pipeline passed.

Personal-fork E2E

The isolated tests used personal-fork PR 11, which is closed, draft, unmerged, marker-only, and label-clean.

The authorized-member, commit-persistence, and non-member scenarios used the current production workflow with only the repository predicate adapted to chzblych/TensorRT-LLM:

  • Authorized Team member: Guard 29673569673 retained the label and created no denial comment.
  • Commit persistence: after the approved PR head changed, the label remained and no synchronize-triggered Guard run appeared.
  • Real non-member GitHub App: driver 29673640225 and Guard 29673644808 removed the label and posted the denial comment. Retained artifact digest: sha256:56ff6931ea189a89d22c743938a1ce5cc2024a5cd6541509d4d937c5ca6f92fd.

For the standard-cancellation scenario, the fork workflow used the same implementation plus a temporary deterministic pause step solely to create a reproducible cancellation window:

  • Driver 29674054263 issued the normal cancellation request.
  • Guard 29674059267 ended with a cancelled workflow conclusion while its Guard job and cleanup step succeeded, removed the label, and posted the denial comment.
  • The accepted artifact passed its embedded SHA256SUMS; digest: sha256:0210abec37b9311998af6979380e2ec97edc6a5a9767e5a8774c8b71425631f8.

Earlier deterministic E2E remains applicable to the unchanged event-binding and concurrency logic:

After testing, the temporary Guard and deterministic pause were removed from fork main, and the retained negative-E2E driver was restored. These personal-fork tests invoked no /bot command, Blossom issue_comment workflow, or production downstream Jenkins job.

The upstream PR was explicitly marked as not requiring L0 with /bot skip; no L0/downstream test workload was dispatched.

Deployment and Merge Order

  1. Update this PR to the latest upstream main, then re-run required checks and automated review.
  2. Confirm that the upstream repository contains TRTLLM_AGENT_SHARED_TOKEN with organization/Team-membership read access.
  3. Merge this PR and verify that the Guard workflow is present on the upstream default branch.
  4. Create the upstream repository label ci: post-merge approved after the Guard is active and before enabling the Jenkins gate.
  5. Merge companion trtllm-github-ci!86.

Deploying the actor-validation workflow first avoids a window in which Jenkins trusts a label before unauthorized additions are being cleaned up.

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@chzblych
chzblych marked this pull request as ready for review July 13, 2026 09:31
@chzblych
chzblych requested review from a team as code owners July 13, 2026 09:31
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Post-merge approval enforcement

Layer / File(s) Summary
Approval validation and cleanup
.github/workflows/post-merge-approval.yml
Adds a label-triggered workflow that verifies the latest labeling actor’s active membership in NVIDIA/trt-llm-ci-approvers, preserves newer approvals during cleanup, and removes invalid labels with a PR comment.
Command guidance and CI documentation
.github/workflows/bot-command.yml, docs/source/developer-guide/ci-overview.md
Documents approval-label requirements for post-merge runs and broad wildcard stage selectors, including persistence and wildcard syntax details.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant ApprovalWorkflow
  participant TeamsAPI
  participant GitHubAPI
  PullRequest->>ApprovalWorkflow: Apply approval label
  ApprovalWorkflow->>GitHubAPI: Find latest label event
  ApprovalWorkflow->>TeamsAPI: Verify labeling actor
  TeamsAPI-->>ApprovalWorkflow: Return membership status
  ApprovalWorkflow->>GitHubAPI: Remove invalid label and post comment
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows the required ticket/type pattern and clearly summarizes the main change.
Description check ✅ Passed The description includes the required sections and enough detail on the change, testing, and checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/test_post_merge_approval_workflow.js:
- Around line 87-129: Update the runValidation test fixture so context.actor and
payload.sender.login use distinct values when sender is present, then assert the
result uses the sender login (for example, retain the expected label actor while
using a different fallback actor). Preserve the sender=false case to verify
context.actor is used when no sender exists.

In @.github/workflows/post-merge-approval.yml:
- Around line 70-103: Update the post-merge approval workflow to serialize or
debounce runs per pull request, then re-check the latest label event and
authorization state immediately before any removeLabel cleanup. Ensure an older
unauthorized run exits without removing a label re-added by a later valid
approval.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 43c183c7-c921-4987-97dc-214454fce7d4

📥 Commits

Reviewing files that changed from the base of the PR and between 01291f9 and 3e82b91.

📒 Files selected for processing (4)
  • .github/scripts/test_post_merge_approval_workflow.js
  • .github/workflows/bot-command.yml
  • .github/workflows/post-merge-approval.yml
  • docs/source/developer-guide/ci-overview.md

Comment thread .github/scripts/test_post_merge_approval_workflow.js Outdated
Comment thread .github/workflows/post-merge-approval.yml

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/source/developer-guide/ci-overview.md (1)

1-1: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the required NVIDIA copyright header.

This modified Markdown file starts directly with the document title and has no NVIDIA copyright header. Add the repository-standard header in a Markdown-safe comment and use the latest meaningful modification year.

As per coding guidelines, all files matching **/* must contain or update the NVIDIA copyright header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/source/developer-guide/ci-overview.md` at line 1, Add the
repository-standard NVIDIA copyright header at the beginning of the Markdown
document using a Markdown-safe comment, and set its year to the latest
meaningful modification year. Keep the existing “Continuous Integration
Overview” title and document content unchanged.

Source: Coding guidelines

🧹 Nitpick comments (1)
.github/workflows/post-merge-approval.yml (1)

18-20: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

pull_request_target dangerous-trigger finding is an expected trade-off here, not a defect.

zizmor's dangerous-triggers rule fires on any pull_request_target use, but this workflow never checks out or executes PR code — the script body is static and only reads timeline/label metadata via the API, so the usual fork-RCE/secret-exfiltration vector doesn't apply. Consider documenting this rationale near the trigger (or adding a suppression entry in zizmor's config, if supported) so the finding doesn't need to be re-litigated on every scan.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/post-merge-approval.yml around lines 18 - 20, Document the
intentional use of pull_request_target beside the trigger in the workflow,
noting that the job runs only static logic and reads timeline/label metadata
through the API without checking out or executing pull-request code.
Alternatively, add the supported zizmor suppression for this expected finding,
preserving the existing trigger behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/post-merge-approval.yml:
- Around line 22-24: Add issues: write to the permissions block in the
post-merge approval workflow, preserving the existing contents and pull-requests
permissions so github.rest.issues.removeLabel can execute successfully.

---

Outside diff comments:
In `@docs/source/developer-guide/ci-overview.md`:
- Line 1: Add the repository-standard NVIDIA copyright header at the beginning
of the Markdown document using a Markdown-safe comment, and set its year to the
latest meaningful modification year. Keep the existing “Continuous Integration
Overview” title and document content unchanged.

---

Nitpick comments:
In @.github/workflows/post-merge-approval.yml:
- Around line 18-20: Document the intentional use of pull_request_target beside
the trigger in the workflow, noting that the job runs only static logic and
reads timeline/label metadata through the API without checking out or executing
pull-request code. Alternatively, add the supported zizmor suppression for this
expected finding, preserving the existing trigger behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f8a7cfaf-7771-40f5-8315-71b47658331e

📥 Commits

Reviewing files that changed from the base of the PR and between 01291f9 and f39f1da.

📒 Files selected for processing (4)
  • .github/scripts/test_post_merge_approval_workflow.js
  • .github/workflows/bot-command.yml
  • .github/workflows/post-merge-approval.yml
  • docs/source/developer-guide/ci-overview.md

Comment thread .github/workflows/post-merge-approval.yml

Copy link
Copy Markdown
Collaborator Author

Addressed the latest CodeRabbit review on head 9d79005:

  • Added an accurate rationale beside pull_request_target: the workflow runs static default-branch API logic and never checks out or executes PR code.
  • Kept least-privilege pull-requests: write; GitHub documents it as sufficient for both label removal and PR timeline comments, and the fork E2E cleanup path already succeeded with that permission only.
  • Did not add a copyright header to docs/source/developer-guide/ci-overview.md: the repository's Markdown documentation convention does not use SPDX headers, and the coding-guideline rule applies to compiled/interpreted OSS source files.

Validation: executable workflow contract test passed, git diff --check passed, and the cross-repository policy contract passed.

@ZhanruiSunCh ZhanruiSunCh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern regarding the interaction between this workflow and the Jenkins gate:

Potential bypass via workflow cancellation / delay:

The clear step condition if: always() && \!cancelled() && ... means the label cleanup is skipped when the workflow run is cancelled. A user with Write access (but not a trt-llm-ci-approvers member) could:

  1. Add the ci: post-merge approved label
  2. Cancel the approval workflow run before the clear step executes
  3. The label remains on the PR
  4. /bot run --post-merge → Jenkins sees the label → dispatches

The same gap exists when the workflow is queued (concurrency group) or delayed (GitHub Actions runner unavailability) — the label is unvalidated during that window.

Since the Jenkins wrapper job already has a GitHub token, consider adding the same membership verification in validatePostMergeApproval() (fetch PR timeline → check label actor membership in trt-llm-ci-approvers) so Jenkins can independently validate regardless of the workflow's execution state.

@dpitman-nvda
dpitman-nvda removed their request for review July 16, 2026 20:40
chzblych added 7 commits July 19, 2026 11:45
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
Signed-off-by: Yanchao Lu <yanchaol@nvidia.com>
@chzblych
chzblych force-pushed the trtllminf-188-post-merge-approval branch from b9e1420 to ebde870 Compare July 19, 2026 05:57

chzblych commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator Author

@ZhanruiSunCh Thanks for raising the cancellation/delay concern in your review.

I agree that making this a strict authorization boundary would require Jenkins to synchronously verify the label actor/Team membership (or consume another trusted approval record). For TRTLLMINF-188 we are intentionally keeping the lower-complexity, best-effort resource-governance model: the GitHub Action validates the actor, and the companion Jenkins change refreshes current label presence before dispatch.

This update covers the normal cancellation path after a Guard job starts:

  • job-level and cleanup-step always() keep fail-closed cleanup eligible;
  • a five-minute timeout bounds a stuck Guard;
  • label comparisons are case-insensitive;
  • isolated E2E driver 29674054263 / Guard 29674059267 verified a standard cancel request, successful cleanup, label removal, and the denial comment. The E2E used the same Guard implementation plus a temporary deterministic pause solely to make the cancellation window reproducible.

Queued-before-start cancellation, force-cancel, runner/service failure, and the immediate asynchronous label-to-dispatch window are not fully covered by this design. Follow-up TRTLLMINF-220 tracks the stronger guarantee and evaluation of a synchronous Jenkins check or another low-complexity approach.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@chzblych

Copy link
Copy Markdown
Collaborator Author

/bot skip --comment "Not tested by L0"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60159 [ skip ] triggered by Bot. Commit: ebde870 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60159 [ skip ] completed with state SUCCESS. Commit: ebde870
Skipping testing for commit ebde870

Link to invocation

@chzblych
chzblych enabled auto-merge (squash) July 19, 2026 10:08
@chzblych
chzblych disabled auto-merge July 19, 2026 10:08
@chzblych
chzblych merged commit 3124bb3 into NVIDIA:main Jul 19, 2026
23 checks passed
@chzblych
chzblych deleted the trtllminf-188-post-merge-approval branch July 19, 2026 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants